package client.management;

/**
 * This class represents a management client of an auction-service. A management
 * client can invoke remotely methods either on an analytics server or on a
 * billing server. Therefore the user can input some commands on the stdin and
 * the management client invokes methods (i.e.: subscribe, unsubscribe,
 * processEvent, ...).
 * 
 * @version 1.0 vom 12.11.2012
 * @author Distributed Group 111 1026312, 1026309
 */

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;

import model.Bill;

import server.analytics.AnalyticsServer;
import server.analytics.Subscription;
import server.billing.BillingServer;
import server.billing.BillingServerSecure;

public class ManagementClient {
	public static void main(String[] args) {
		if (args.length != 2 && args.length != 3) {
			System.err
					.println("Usage: ManagementClient <analytics_binding> <billing_binding>");
			System.exit(1);
		}

		BufferedReader inReader = new BufferedReader(new InputStreamReader(
				System.in));
		String analyticsName = args[0];
		String billingName = args[1];
		Registry registry = null;
		BillingServer billingServer = null;
		AnalyticsServer analyticsServer = null;
		BillingServerSecure billingServerSecure = null;
		ManagementClientNotifierImpl clientNotifier = null;
		Subscription subscription = null;

		try {
			clientNotifier = new ManagementClientNotifierImpl();
		} catch (RemoteException e) {
			System.err
					.println("ERROR: Creating or exporting error of callback-object for notifications: "
							+ e.getMessage());
		}

		// Read properties from registry.properties
		int registryPort = -1;
		String registryHost = "";
		java.io.InputStream is = ClassLoader
				.getSystemResourceAsStream("registry.properties");
		if (is != null) {
			java.util.Properties props = new java.util.Properties();
			try {
				props.load(is);
				registryPort = Integer.parseInt(props
						.getProperty("registry.port"));
				registryHost = props.getProperty("registry.host");
			} catch (IOException e) {
				System.err.println("ERROR: Reading from registry.properties:"
						+ e.getMessage());
			} catch (NumberFormatException e) {
				System.err
						.println("ERROR: Values in registry.properties file are no integers!");
			} finally {
				try {
					is.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		} else {
			System.err.println("Properties file not found!");
		}

		try { // get analytics object from registry
			registry = LocateRegistry.getRegistry(registryHost, registryPort);
			analyticsServer = (AnalyticsServer) registry.lookup(analyticsName);
		} catch (RemoteException e) {
			System.err.println("ERROR: RemoteException: " + e.getMessage());
		} catch (NotBoundException e) {
			System.err.println("Caution: Remote object analytics not bound: "
					+ e.getMessage());
		}
		try { // get billing object from registry
			billingServer = (BillingServer) registry.lookup(billingName);
		} catch (RemoteException e) {
			System.err.println("ERROR: RemoteException: " + e.getMessage());
		} catch (NotBoundException e) {
			System.err.println("Caution: Remote object billing not bound: "
					+ e.getMessage());
		}

		// if 3 arguments then the client shall be a loadTestManagementClient
		if (args.length == 3) {
			try {
				if (analyticsServer != null) {
					subscription = analyticsServer.subscribe(".*",
							clientNotifier);
					subscription.addRegex(".*");
					clientNotifier.setState("auto");
					System.out
							.println("Subscription added with filter: '.*' on AnalyticsServer");
				} else {
					System.out.println("ERROR: AnalyticsServer not available!");
					System.exit(1);
				}

			} catch (RemoteException e) {
				System.err
						.println("Error loadTestManagementClient could not subscribe for all events: "
								+ e.getMessage());
			}
		}

		String userInput = "";
		try {
			while ((userInput = inReader.readLine()) != null) {

				if (userInput.equals("!exit")) {
					break;
				} else if (userInput.startsWith("!login")) {
					if (userInput.split(" ").length != 3) {
						System.out
								.println("Usage: !login <username> <password>");
						continue;
					}
					try {
						if (billingServerSecure != null) {
							System.out.println("You are already logged in.");
							continue;
						}
						if (billingServer == null) {
							System.out.println("Billingserver not available.");
							continue;
						}
						billingServerSecure = billingServer.login(
								userInput.split(" ")[1],
								userInput.split(" ")[2]);
						if (billingServerSecure != null) {
							System.out.println(userInput.split(" ")[1]
									+ " successfully logged in");
						} else {
							System.out
									.println("Couldn't login, please check username and password.");
						}
					} catch (RemoteException e) {
						System.err.println("ERROR: RemoteException login: "
								+ e.getMessage());
					}
				}

				else if (userInput.startsWith("!logout")) {
					if (!userInput.equals("!logout")) {
						System.out.println("Usage: !logout");
						continue;
					}
					if (billingServerSecure == null) {
						System.out
								.println("Couldn't log out. You have to log in first!");
						continue;
					}
					billingServerSecure = null;
					System.out.println("Successfully logged out.");
				}

				else if (userInput.startsWith("!subscribe")) {
					if (userInput.split(" ").length != 2) {
						System.out.println("Usage: !subscribe <filterRegex>");
						continue;
					}
					try {
						if (analyticsServer == null) {
							System.out
									.println("AnalyticsServer not available!");
							continue;
						}
						if (subscription == null) {
							subscription = analyticsServer.subscribe("",
									clientNotifier);
						}
						int id = subscription.addRegex(userInput.split(" ")[1]);
						if (id >= 0) {
							System.out.println("Created subscription with ID "
									+ id + " for events using filter '"
									+ userInput.split(" ")[1] + "'");
						} else {
							System.out
									.println("Couldn't create a subscription.\n"
											+ "You may already subscribed with that filter: '"
											+ userInput.split(" ")[1] + "'");
						}
					} catch (RemoteException e) {
						System.err
								.println("ERROR: RemoteException subscribing: "
										+ e.getMessage());
					}
				}

				else if (userInput.startsWith("!unsubscribe")) {
					if (userInput.split(" ").length != 2) {
						System.out
								.println("Usage: !unsubscribe <subscriptionID>");
						continue;
					}
					try {
						Integer.parseInt(userInput.split(" ")[1]);
					} catch (NumberFormatException e) {
						System.out
								.println("Usage: !unsubscribe <subscriptionID>\n"
										+ "subscriptionID must be integer-numeric");
					}

					try {
						if (subscription == null) {
							System.out.println("You have no subscription");
							continue;
						}
						if (subscription.removeRegex(Integer.parseInt(userInput
								.split(" ")[1]))) {
							System.out.println("subscription "
									+ userInput.split(" ")[1] + " terminated");
						} else {
							System.out.println("subscription with id "
									+ userInput.split(" ")[1]
									+ " couldn't be terminated");
						}
					} catch (RemoteException e) {
						System.err
								.println("ERROR: RemoteException unsubscribing: "
										+ e.getMessage());
					}

				}

				else if (userInput.startsWith("!steps")) {
					if (!userInput.equals("!steps")) {
						System.out.println("Usage: !steps");
						continue;
					}
					if (billingServerSecure == null) {
						System.out
								.println("ERROR: You are currently not logged in.");
						continue;
					}

					try {
						System.out.println(billingServerSecure.getPriceSteps()
								.toString());
					} catch (RemoteException e) {
						System.out
						.println("Error: RemoteException steps: "
								+ e.getMessage());
					}
				}

				else if (userInput.startsWith("!addStep")) {
					double startPrice, endPrice, fixedPrice, variablePricePercent;
					if (userInput.split(" ").length != 5) {
						System.out
								.println("Usage: !addStep <startPrice> <endPrice> <fixedPrice> <variablePricePercent>");
						continue;
					}
					try {
						startPrice = Double
								.parseDouble(userInput.split(" ")[1]);
						String upper = userInput.split(" ")[2];
						if ("INFINITY".equals(upper)
								|| "infinity".equals(upper)
								|| "Infinity".equals(upper)) {
							endPrice = 0;
						} else {
							endPrice = Double
									.parseDouble(userInput.split(" ")[2]);
						}
						fixedPrice = Double
								.parseDouble(userInput.split(" ")[3]);
						variablePricePercent = Double.parseDouble(userInput
								.split(" ")[4]);
					} catch (NumberFormatException e) {
						System.out
								.println("Usage: !addStep <startPrice> <endPrice> <fixedPrice> <variablePricePercent>"
										+ "All arguments must be numeric or 'infinity' for <endPrice>.");
						continue;
					}

					if (billingServerSecure == null) {
						System.out
								.println("ERROR: You are currently not logged in.");
						continue;
					}
					try {
						billingServerSecure.createPriceStep(startPrice,
								endPrice, fixedPrice, variablePricePercent);
						String upper = "" + endPrice;
						if (endPrice == 0) {
							upper = "INFINITY";
						}
						System.out.println("Step [" + startPrice + " " + upper
								+ "] successfully added");
					} catch (RemoteException e) {
						System.out
						.println("Error: RemoteException addStep: "
								+ e.getMessage());
					}
				}

				else if (userInput.startsWith("!removeStep")) {
					double startPrice, endPrice;
					if (userInput.split(" ").length != 3) {
						System.out
								.println("Usage: !removeStep <startPrice> <endPrice>");
						continue;
					}

					try {
						startPrice = Double
								.parseDouble(userInput.split(" ")[1]);
						String upper = userInput.split(" ")[2];
						if ("INFINITY".equals(upper)
								|| "infinity".equals(upper)
								|| "Infinity".equals(upper)) {
							endPrice = 0;
						} else {
							endPrice = Double.parseDouble(upper);
						}
					} catch (NumberFormatException e) {
						System.out
								.println("Usage: !removeStep <startPrice> <endPrice>\n"
										+ "All arguments must be numeric or 'infinity' for <endPrice>.");
						continue;
					}
					if (billingServerSecure == null) {
						System.out
								.println("ERROR: You are currently not logged in.");
						continue;
					}

					try {
						billingServerSecure.deletePriceStep(startPrice,
								endPrice);
						String upper = "" + endPrice;
						if (endPrice == 0) {
							upper = "INFINITY";
						}
						System.out.println("Price step [" + startPrice + " "
								+ upper + "] successfully removed");
					} catch (RemoteException e) {
						System.out
								.println("Error: RemoteException removeStep: "
										+ e.getMessage());
					}
				}

				else if (userInput.startsWith("!bill")) {
					if (userInput.split(" ").length != 2) {
						System.out.println("Usage: !bill <userName>");
						continue;
					}
					if (billingServerSecure == null) {
						System.out
								.println("ERROR: You are currently not logged in.");
						continue;
					}

					Bill bill = null;
					try {
						bill = billingServerSecure
								.getBill(userInput.split(" ")[1]);
					} catch (RemoteException e) {
						System.out
								.println("Error: RemoteException removeStep: "
										+ e.getMessage());
					}

					if (bill != null) {
						System.out.println(bill.toString());
					} else {
						System.out
								.println("User "
										+ userInput.split(" ")[1]
										+ " is not registered or never billed an auction.");
					}
				}

				else if (userInput.startsWith("!auto")) {
					if (!userInput.equals("!auto")) {
						System.out.println("Usage: !auto");
						continue;
					}

					clientNotifier.setState("auto");
					System.out.println("Printstate changed to: auto");
					clientNotifier.print();
				}

				else if (userInput.startsWith("!hide")) {
					if (!userInput.equals("!hide")) {
						System.out.println("Usage: !hide");
						continue;
					}

					clientNotifier.setState("hide");
					System.out.println("Printstate changed to: hide");
				}

				else if (userInput.startsWith("!print")) {
					if (!userInput.equals("!print")) {
						System.out.println("Usage: !print");
						continue;
					}

					clientNotifier.print();
				}

				else {
					System.out
							.println("Valid commands: !login, !logout, !steps, "
									+ "!addStep, !removeStep, !subscribe, "
									+ "!unsubscribe, !bill, !auto, !hide, !print and !exit");
				}
			}
		} catch (IOException e) {
			System.err.println("Error reading stdin: " + e.getMessage());
		}

		// free ressources
		try {
			inReader.close();
			UnicastRemoteObject.unexportObject(clientNotifier, true);
			subscription = null;
			billingServerSecure = null;
			System.out.println("Management-Client shut down successfully!");
		} catch (IOException e) {
			System.err.println("ERROR: Clearing ressources: " + e.getMessage());
		}
	} // end of main
}